home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / dev / devSCSIDisk.c < prev    next >
C/C++ Source or Header  |  1991-08-11  |  29KB  |  1,007 lines

  1. /* 
  2.  * devScsiDisk.c --
  3.  *
  4.  *      SCSI Command formatter for SCSI type 0 (Direct Access Devices.) 
  5.  *    This file implements the BlockDevice interface to SCSI disk.
  6.  *
  7.  * Copyright 1986 Regents of the University of California
  8.  * All rights reserved.
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/kernel/dev/RCS/devSCSIDisk.c,v 9.16 91/06/06 11:21:38 mendel Exp $ SPRITE (Berkeley)";
  20. #endif not lint
  21.  
  22.  
  23. #include "sprite.h"
  24. #include "stdio.h"
  25. #include "fs.h"
  26. #include "dev.h"
  27. #include "devInt.h"
  28. #include "scsi.h"
  29. #include "scsiDevice.h"
  30. #include "devDiskLabel.h"
  31. #include "devDiskStats.h"
  32. #include "devBlockDevice.h"
  33. #include "stdlib.h"
  34. #include "bstring.h"
  35. #include "dev/scsi.h"
  36. #include "dbg.h"
  37. #include "fsdm.h"
  38.  
  39. typedef struct DiskMap {
  40.     int     firstSector;
  41.     int     sizeInSectors;
  42. } DiskMap;
  43.  
  44. /*
  45.  * State info for an SCSI Disk.  This gets allocated and filled in by
  46.  * the attach procedure. 
  47.  */
  48. typedef struct ScsiDisk {
  49.     DevBlockDeviceHandle blockHandle; /* Must be FIRST field. */
  50.     ScsiDevice    *devPtr;          /* SCSI Device we have open. */
  51.     int            partition;  /* What partition we want. A partition number
  52.                  * of -1 means the whole disk.
  53.                  */
  54.     int sizeInSectors;        /* The number of sectors on disk */
  55.     DiskMap map[DEV_NUM_DISK_PARTS];    /* The partition map */
  56.     int type;        /* Type of the drive, needed for error checking */
  57.     DevDiskStats *diskStatsPtr;    /* Area for disk stats. */    
  58. } ScsiDisk;
  59.  
  60. typedef struct ScsiDiskCmd {
  61.     ScsiDisk    *diskPtr;    /* Target disk of command. */
  62.     ScsiCmd    scsiCmd;    /* SCSI command to send to disk. */
  63. } ScsiDiskCmd;
  64.  
  65.  
  66. #define    SCSI_DISK_SECTOR_SIZE    DEV_BYTES_PER_SECTOR
  67.  
  68. #define    RequestDone(requestPtr,status,byteCount) \
  69.     ((requestPtr)->doneProc)((requestPtr),(status),(byteCount))
  70.  
  71. static ReturnStatus DiskError();
  72. static Boolean    ScsiDiskIdleCheck();
  73.  
  74.  
  75. /*
  76.  *----------------------------------------------------------------------
  77.  *
  78.  * FillInLabel --
  79.  *
  80.  *    Read the label of the disk and record the partitioning info.
  81.  *
  82.  * Results:
  83.  *    None.
  84.  *
  85.  * Side effects:
  86.  *    Define the disk partitions that determine which part of the
  87.  *    disk each different disk device uses.
  88.  *
  89.  *----------------------------------------------------------------------
  90.  */
  91. static ReturnStatus
  92. FillInLabel(devPtr,diskPtr)
  93.     ScsiDevice         *devPtr; /* SCSI Handle for device. */
  94.     ScsiDisk         *diskPtr;  /* Disk state stucture to read label. */
  95. {
  96.     register ReturnStatus    status;
  97.     ScsiCmd            labelReadCmd;
  98.     Sun_DiskLabel        *sunLabelPtr;
  99.     Dec_DiskLabel        *decLabelPtr;
  100.     Fsdm_DiskHeader        *diskHdrPtr;
  101.     char            labelBuffer[SCSI_DISK_SECTOR_SIZE];
  102.     unsigned char        statusByte;
  103.     int                senseLength;
  104.     char            senseBuffer[SCSI_MAX_SENSE_LEN];
  105.     int                byteCount;
  106.     int                part;
  107.     Boolean            printLabel = FALSE;
  108.  
  109. #ifdef DEBUG
  110.     printLabel = TRUE;
  111. #endif
  112.  
  113.     /*
  114.      * The label of a SCSI disk normally resides in the first sector. Format
  115.      * and send a SCSI READ command to fetch the sector.
  116.      */
  117.     DevScsiGroup0Cmd(devPtr, SCSI_READ, 0, 1,&labelReadCmd);
  118.     labelReadCmd.buffer = labelBuffer;
  119.     labelReadCmd.dataToDevice = FALSE;
  120.     labelReadCmd.bufferLen = SCSI_DISK_SECTOR_SIZE;
  121.     senseLength = SCSI_MAX_SENSE_LEN;
  122.     status = DevScsiSendCmdSync(devPtr,&labelReadCmd,&statusByte,&byteCount,
  123.                 &senseLength, senseBuffer);
  124.     if (status == SUCCESS) {
  125.     status = DiskError(diskPtr,statusByte, senseLength, senseBuffer);
  126.     }
  127.     if ((status == SUCCESS) && (byteCount < sizeof(Sun_DiskLabel))) {
  128.     status = DEV_EARLY_CMD_COMPLETION;
  129.     }
  130.     if (status != SUCCESS) {
  131.     return(status);
  132.     }
  133.     sunLabelPtr = (Sun_DiskLabel *) labelBuffer;
  134.     if (sunLabelPtr->magic == SUN_DISK_MAGIC) {
  135.     /*
  136.      * XXX - Should really check if label is valid.
  137.      */
  138.     if (printLabel) {
  139.         printf("%s: %s\n", devPtr->locationName, sunLabelPtr->asciiLabel);
  140.     }
  141.  
  142.     diskPtr->sizeInSectors = sunLabelPtr->numSectors * 
  143.                 sunLabelPtr->numHeads * sunLabelPtr->numCylinders;
  144.     
  145.     if (printLabel) {
  146.         printf(" Partitions ");
  147.     }
  148.     for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
  149.         diskPtr->map[part].firstSector = sunLabelPtr->map[part].cylinder *
  150.                          sunLabelPtr->numHeads * 
  151.                          sunLabelPtr->numSectors;
  152.         diskPtr->map[part].sizeInSectors =
  153.                     sunLabelPtr->map[part].numBlocks;
  154.         if (printLabel) {
  155.         printf(" (%d,%d)", diskPtr->map[part].firstSector,
  156.                        diskPtr->map[part].sizeInSectors);
  157.         }
  158.     }
  159.     if (printLabel) {
  160.         printf("\n");
  161.     }
  162.  
  163.     return(SUCCESS);
  164.     }
  165.     /*
  166.      * The disk isn't in SUN format so try Sprite format.
  167.      */
  168.     diskHdrPtr = (Fsdm_DiskHeader *)labelBuffer;
  169.     if (diskHdrPtr->magic == FSDM_DISK_MAGIC) {
  170.     /*
  171.      * XXX - Should really check if label is valid.
  172.      */
  173.     if (printLabel) {
  174.         printf("%s: %s\n", devPtr->locationName, diskHdrPtr->asciiLabel);
  175.     }
  176.  
  177.     diskPtr->sizeInSectors = diskHdrPtr->numSectors * 
  178.                  diskHdrPtr->numHeads *
  179.                      diskHdrPtr->numCylinders;
  180.  
  181.     if (printLabel) {
  182.         printf(" Partitions ");
  183.     }
  184.     for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
  185.         diskPtr->map[part].firstSector = 
  186.                 diskHdrPtr->map[part].firstCylinder *
  187.                 diskHdrPtr->numHeads * diskHdrPtr->numSectors;
  188.         diskPtr->map[part].sizeInSectors =
  189.                 diskHdrPtr->map[part].numCylinders *
  190.                 diskHdrPtr->numHeads * diskHdrPtr->numSectors;
  191.         if (printLabel) {
  192.         printf(" (%d,%d)", diskPtr->map[part].firstSector,
  193.                    diskPtr->map[part].sizeInSectors);
  194.         }
  195.     }
  196.     if (printLabel) {
  197.         printf("\n");
  198.     }
  199.     return(SUCCESS);
  200.     }
  201.     /*
  202.      * The disk isn't in SUN or Sprite format so try Dec format.
  203.      * We have to read the right sector first.
  204.      */
  205.     DevScsiGroup0Cmd(devPtr, SCSI_READ, DEC_LABEL_SECTOR, 1,&labelReadCmd);
  206.     labelReadCmd.buffer = labelBuffer;
  207.     labelReadCmd.dataToDevice = FALSE;
  208.     labelReadCmd.bufferLen = SCSI_DISK_SECTOR_SIZE;
  209.     senseLength = SCSI_MAX_SENSE_LEN;
  210.     status = DevScsiSendCmdSync(devPtr,&labelReadCmd,&statusByte,&byteCount,
  211.                 &senseLength, senseBuffer);
  212.     if (status == SUCCESS) {
  213.     status = DiskError(diskPtr,statusByte, senseLength, senseBuffer);
  214.     }
  215.     if ((status == SUCCESS) && (byteCount < sizeof(Dec_DiskLabel))) {
  216.     status = DEV_EARLY_CMD_COMPLETION;
  217.     }
  218.     if (status != SUCCESS) {
  219.     return(status);
  220.     }
  221.     decLabelPtr = (Dec_DiskLabel *) labelBuffer;
  222.     if (decLabelPtr->magic == DEC_LABEL_MAGIC) {
  223.     /*
  224.      * XXX - Should really check if label is valid.
  225.      */
  226.     if (decLabelPtr->spriteMagic != FSDM_DISK_MAGIC) {
  227.         printf("Disk needs Sprite-modified Dec label\n");
  228.     }
  229.     if (decLabelPtr->version != DEC_LABEL_VERSION) {
  230.         printf("Disk label version mismatch: %x vs %x\n",
  231.             decLabelPtr->version, DEC_LABEL_VERSION);
  232.     }
  233.     if (printLabel) {
  234.         printf("%s: %s\n", devPtr->locationName, decLabelPtr->asciiLabel);
  235.     }
  236.  
  237.     diskPtr->sizeInSectors = decLabelPtr->numSectors * 
  238.                 decLabelPtr->numHeads * decLabelPtr->numCylinders;
  239.     
  240.     if (printLabel) {
  241.         printf(" Partitions ");
  242.     }
  243.     for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
  244.         diskPtr->map[part].firstSector =
  245.             decLabelPtr->map[part].offsetBytes / DEV_BYTES_PER_SECTOR;
  246.         diskPtr->map[part].sizeInSectors =
  247.             decLabelPtr->map[part].numBytes / DEV_BYTES_PER_SECTOR;
  248.         if (printLabel) {
  249.         printf(" (%d,%d)", diskPtr->map[part].firstSector,
  250.                        diskPtr->map[part].sizeInSectors);
  251.         }
  252.     }
  253.     if (printLabel) {
  254.         printf("\n");
  255.     }
  256.  
  257.     return(SUCCESS);
  258.     }
  259.     return(FAILURE);
  260. }
  261.  
  262. /*
  263.  *----------------------------------------------------------------------
  264.  *
  265.  * ScsiDiskIdleCheck --
  266.  *
  267.  *    Routine for the Disk Stats module to use to determine the idleness
  268.  *    for a disk.
  269.  *
  270.  * Results:
  271.  *    TRUE if the disk pointed to by clientData is idle, FALSE otherwise.
  272.  *
  273.  * Side effects:
  274.  *    None.
  275.  *
  276.  *----------------------------------------------------------------------
  277.  */
  278. /*ARGSUSED*/
  279. static Boolean
  280. ScsiDiskIdleCheck(clientData, diskStatsPtr) 
  281.     ClientData        clientData;        /* Unused for SCSI disks. */
  282.     DevDiskStats    *diskStatsPtr;
  283. {
  284.     Boolean        retVal;
  285.  
  286.     MASTER_LOCK(&(diskStatsPtr->mutex));
  287.     retVal = !(diskStatsPtr->busy);
  288.     MASTER_UNLOCK(&(diskStatsPtr->mutex));
  289.  
  290.     return retVal;
  291.  
  292. }
  293.  
  294. /*
  295.  *----------------------------------------------------------------------
  296.  *
  297.  * InitDisk --
  298.  *
  299.  *    Initialize the device driver state for a SCSI Disk. 
  300.  *
  301.  * Results:
  302.  *    The ScsiDisk structure. NIL - if there is an error attaching the
  303.  *    disk.
  304.  *
  305.  * Side effects:
  306.  *    The disk's label is read and saved in a ScsiDisk structure.  This
  307.  *    is allocated here.
  308.  *
  309.  *----------------------------------------------------------------------
  310.  */
  311. static ScsiDisk *
  312. InitDisk(devPtr,readLabel)
  313.     ScsiDevice    *devPtr; /* SCSI Handle for device. */
  314.     Boolean    readLabel;   /* TRUE if we should read and fill in label 
  315.                   * fields. */
  316. {
  317.     ScsiDisk    disk, *diskPtr;
  318.     ReturnStatus status;
  319.     int        retry = 3;
  320.     bzero((char *) &disk, sizeof(ScsiDisk));
  321.     /*
  322.      * Check that the disk is on-line.  
  323.      * We do this check twice because it appears that dec rz55 
  324.      * drives always indicate that they are ready after powerup,
  325.      * even if their not.
  326.      */
  327.     status = DevScsiTestReady(devPtr);
  328.     status = DevScsiTestReady(devPtr);
  329.     if (status != SUCCESS) {
  330.     if (status != DEV_OFFLINE) {
  331.         return((ScsiDisk *) NIL);
  332.     }
  333.     /*
  334.      * Do this loop a few times because Quantum drives appear to respond
  335.      * to the first start request before they are actually on-line.
  336.      */
  337.     while (retry > 0) {
  338.         /*
  339.          * Try and start the unit.
  340.          */
  341.         status = DevScsiStartStopUnit(devPtr, TRUE);
  342.         if (status != SUCCESS) {
  343.         return((ScsiDisk *) NIL);
  344.         }
  345.         /*
  346.          * Make sure the unit is ready.
  347.          */
  348.         status = DevScsiTestReady(devPtr);
  349.         if (status == SUCCESS) {
  350.         break;
  351.         }
  352.         retry--;
  353.     }
  354.     }
  355.     disk.devPtr = devPtr;
  356.     if (readLabel) {
  357.     status = FillInLabel(devPtr,&disk);
  358.     if (status != SUCCESS) {
  359.         return((ScsiDisk *) NIL);
  360.     }
  361.     } 
  362.  
  363.     /*
  364.      * Return a malloced copy of the structure we filled in.
  365.      */
  366.     diskPtr = (ScsiDisk *) malloc(sizeof(ScsiDisk));
  367.     *diskPtr = disk;
  368.     return(diskPtr);
  369. }
  370.  
  371. /*
  372.  *----------------------------------------------------------------------
  373.  *
  374.  * DiskDoneProc --
  375.  *
  376.  *    Call back routine for request to SCSI Disk. 
  377.  *
  378.  * Results:
  379.  *    None.
  380.  *
  381.  * Side effects:
  382.  *    Request call may be woken up.
  383.  *
  384.  *----------------------------------------------------------------------
  385.  */
  386.  
  387. static int
  388. DiskDoneProc(scsiCmdPtr, status, statusByte, byteCount, senseLength, 
  389.          senseDataPtr)
  390.     ScsiCmd    *scsiCmdPtr;    /* Request that finished. */
  391.     ReturnStatus  status;    /* Error of request. */
  392.     unsigned char statusByte;    /* SCSI status byte of request. */
  393.     int        byteCount;    /* Number of bytes transferred. */
  394.     int        senseLength;    /* Length of sense data returned. */
  395.     Address    senseDataPtr;    /* Sense data. */
  396. {
  397.     DevBlockDeviceRequest *requestPtr;
  398.     ScsiDisk    *diskPtr;
  399.  
  400.     requestPtr = (DevBlockDeviceRequest *) (scsiCmdPtr->clientData);
  401.     diskPtr = ((ScsiDiskCmd *) (requestPtr->ctrlData))->diskPtr;
  402.  
  403.     MASTER_LOCK(&(diskPtr->diskStatsPtr->mutex));
  404.     diskPtr->diskStatsPtr->busy--;
  405.     if (requestPtr->operation == FS_READ) {
  406.     diskPtr->diskStatsPtr->diskStats.diskReads += 
  407.                 byteCount/DEV_BYTES_PER_SECTOR;
  408.     } else {
  409.     diskPtr->diskStatsPtr->diskStats.diskWrites += 
  410.                 byteCount/DEV_BYTES_PER_SECTOR;
  411.     }
  412.     MASTER_UNLOCK(&(diskPtr->diskStatsPtr->mutex));
  413.  
  414.     /*
  415.      * If request suffered an HBA error or got no error we notify the
  416.      * caller that the request is done.
  417.      */
  418.     if ((status != SUCCESS) || (statusByte == 0)) {
  419.     RequestDone(requestPtr,status,byteCount);
  420.     return 0;
  421.     }
  422.     /*
  423.      * Otherwise we have a SCSI command that returned an error. 
  424.      */
  425.     status = DiskError(diskPtr, statusByte, senseLength, senseDataPtr);
  426.     RequestDone(requestPtr,status,byteCount);
  427.     return 0;
  428.  
  429. }
  430.  
  431. /*
  432.  *----------------------------------------------------------------------
  433.  *
  434.  * SendCmdToDevice --
  435.  *
  436.  *    Translate a Block Device request into and SCSI command and send it
  437.  *    to the disk device.
  438.  *
  439.  * Results:
  440.  *    SUCCESS is the command is sent otherwise a Sprite Error code.
  441.  *
  442.  * Side effects:
  443.  *    Disk may be read or written.
  444.  *
  445.  *----------------------------------------------------------------------
  446.  */
  447. static ReturnStatus
  448. SendCmdToDevice(diskPtr, requestPtr, firstSector, lengthInSectors)
  449.     ScsiDisk    *diskPtr;
  450.     DevBlockDeviceRequest *requestPtr;
  451.     unsigned int    firstSector;
  452.     unsigned int    lengthInSectors;
  453. {
  454.     int        cmd;
  455.     ScsiDiskCmd     *diskCmdPtr = (ScsiDiskCmd *) (requestPtr->ctrlData);
  456.     ReturnStatus status;
  457.  
  458.     if (sizeof(ScsiDiskCmd) > sizeof((requestPtr->ctrlData))) {
  459.     panic("ScsiDISK: command block bigger than controller data\n");
  460.     return FAILURE;
  461.     }
  462.     if (firstSector <= 0x1fffff) {
  463.     cmd = (requestPtr->operation == FS_READ) ? SCSI_READ : SCSI_WRITE;
  464.     status = DevScsiGroup0Cmd(diskPtr->devPtr,cmd, firstSector, 
  465.             lengthInSectors, &(diskCmdPtr->scsiCmd));
  466.     if (status != SUCCESS) {
  467.         return FAILURE;
  468.     }
  469.     } else {
  470.     ScsiReadExtCmd    *cmdPtr;
  471.     /*
  472.      * The offset is too big for the standard 6-byte SCSI read and
  473.      * write commands.  We have to use the extended version.  Perhaps
  474.      * we should always use the extended version?
  475.      */
  476.     if (lengthInSectors > 0xffff) {
  477.         printf("SendCmdToDevice: too many sectors (%d > %d)\n",
  478.         lengthInSectors, 0xffff);
  479.         return FAILURE;
  480.     }
  481.     bzero((char *) &(diskCmdPtr->scsiCmd), sizeof(ScsiCmd));
  482.     diskCmdPtr->scsiCmd.commandBlockLen = sizeof(ScsiReadExtCmd);
  483.     cmdPtr = (ScsiReadExtCmd *) (diskCmdPtr->scsiCmd.commandBlock);
  484.     cmdPtr->command = (requestPtr->operation == FS_READ) ? 
  485.         SCSI_READ_EXT : SCSI_WRITE_EXT;
  486.     cmdPtr->unitNumber = diskPtr->devPtr->LUN;
  487.     cmdPtr->highAddr = ((firstSector >> 24) & 0xff);
  488.     cmdPtr->highMidAddr = ((firstSector >> 16) & 0xff);
  489.     cmdPtr->lowMidAddr = ((firstSector >> 8) & 0xff);
  490.     cmdPtr->lowAddr = ((firstSector) & 0xff);
  491.     cmdPtr->highCount = ((lengthInSectors >> 8) & 0xff);
  492.     cmdPtr->lowCount = ((lengthInSectors) & 0xff);
  493.     }
  494.     diskCmdPtr->scsiCmd.buffer = requestPtr->buffer;
  495.     diskCmdPtr->scsiCmd.bufferLen = lengthInSectors * SCSI_DISK_SECTOR_SIZE;
  496.     diskCmdPtr->scsiCmd.dataToDevice = (requestPtr->operation == FS_WRITE);
  497.     diskCmdPtr->scsiCmd.doneProc = DiskDoneProc;
  498.     diskCmdPtr->scsiCmd.clientData = (ClientData) requestPtr;
  499.     diskCmdPtr->diskPtr = diskPtr;
  500.  
  501.     MASTER_LOCK(&(diskPtr->diskStatsPtr->mutex));
  502.     diskPtr->diskStatsPtr->busy++;
  503.     MASTER_UNLOCK(&(diskPtr->diskStatsPtr->mutex));
  504.  
  505.     DevScsiSendCmd(diskPtr->devPtr,&(diskCmdPtr->scsiCmd));
  506.     return SUCCESS;
  507. }
  508.  
  509. /*
  510.  *----------------------------------------------------------------------
  511.  *
  512.  * DiskError --
  513.  *
  514.  *    Map SCSI errors indicated by the sense data into Sprite ReturnStatus
  515.  *    and error message. This proceedure handles two types of 
  516.  *    sense data Class 0 and class 7.
  517.  *
  518.  * Results:
  519.  *    A sprite error code.
  520.  *
  521.  * Side effects:
  522.  *    None.
  523.  *
  524.  *----------------------------------------------------------------------
  525.  */
  526. static ReturnStatus
  527. DiskError(diskPtr, statusByte, senseLength, senseDataPtr)
  528.     ScsiDisk     *diskPtr;    /* SCSI disk that's complaining. */
  529.     unsigned char statusByte;    /* The status byte of the command. */
  530.     int         senseLength;    /* Length of SCSI sense data in bytes. */
  531.     char     *senseDataPtr;    /* Sense data. */
  532. {
  533.     ReturnStatus status;
  534.     ScsiStatus *statusPtr = (ScsiStatus *) &statusByte;
  535.     ScsiClass0Sense *sensePtr = (ScsiClass0Sense *) senseDataPtr;
  536.     char    *name = diskPtr->devPtr->locationName;
  537.     char    errorString[MAX_SCSI_ERROR_STRING];
  538.  
  539.     /*
  540.      * Check for status byte to see if the command returned sense
  541.      * data. If no sense data exists then we only have the status
  542.      * byte to look at.
  543.      */
  544.     if (!statusPtr->check) {
  545.     if (SCSI_RESERVED_STATUS(statusByte) || statusPtr->intStatus) {
  546.         printf("Warning: SCSI Disk at %s unknown status byte 0x%x\n",
  547.            name, statusByte);
  548.         return SUCCESS;
  549.     } 
  550.     if (statusPtr->busy) {
  551.         return DEV_OFFLINE;
  552.     }
  553.     return SUCCESS;
  554.     }
  555.     if (senseLength == 0) {
  556.      printf("Warning: SCSI Disk %s error: no sense data\n", name);
  557.      return DEV_NO_SENSE;
  558.     }
  559.     if (DevScsiMapClass7Sense(senseLength, senseDataPtr,&status, errorString)) {
  560.     if (errorString[0]) {
  561.          printf("Warning: SCSI Disk %s error: %s\n", name, errorString);
  562.     }
  563.     return status;
  564.     }
  565.  
  566.     /*
  567.      * If its not a class 7 error it must be Old style sense data..
  568.      */
  569.     if (sensePtr->error == SCSI_NO_SENSE_DATA) {        
  570.     status = SUCCESS;
  571.     } else {
  572.     int class = (sensePtr->error & 0x70) >> 4;
  573.     int code = sensePtr->error & 0xF;
  574.     int addr;
  575.     addr = (sensePtr->highAddr << 16) |
  576.         (sensePtr->midAddr << 8) |
  577.         sensePtr->lowAddr;
  578.     printf("Warning: SCSI disk at %s sense error (%d-%d) at <%x> ",
  579.             name, class, code, addr);
  580.     if (devScsiNumErrors[class] > code) {
  581.         printf("%s", devScsiErrors[class][code]);
  582.      }
  583.      printf("\n");
  584.      status = DEV_HARD_ERROR;
  585.     }
  586.     return status;
  587. }
  588. /*
  589.  * This code is for the raid people to test out HBA/disks pairs 
  590.  * by bypassing most of Sprite.
  591.  * Mendel 9/12/89
  592.  */
  593.  
  594. #include <dev/hbatest.h>
  595. /*ARGSUSED*/
  596. static int
  597. DiskHBATestDoneProc(scsiCmdPtr, status, statusByte, byteCount, senseLength, 
  598.          senseDataPtr)
  599.     ScsiCmd    *scsiCmdPtr;    /* Request that finished. */
  600.     ReturnStatus  status;    /* Error of request. */
  601.     unsigned char statusByte;    /* SCSI status byte of request. */
  602.     int        byteCount;    /* Number of bytes transferred. */
  603.     int        senseLength;    /* Length of sense data returned. */
  604.     Address    senseDataPtr;    /* Sense data. */
  605. {
  606.     ReturnStatus *errorStatusPtr = (ReturnStatus *) (scsiCmdPtr->clientData);
  607.     ScsiStatus *statusPtr = (ScsiStatus *) &statusByte;
  608.     char    errorString[MAX_SCSI_ERROR_STRING];
  609.     ScsiClass0Sense *sensePtr = (ScsiClass0Sense *) senseDataPtr;
  610.     /*
  611.      * Check for status byte to see if the command returned sense
  612.      * data. If no sense data exists then we only have the status
  613.      * byte to look at.
  614.      */
  615.     if ((status == SUCCESS) && !statusPtr->check) {
  616.     return 0;
  617.     }
  618.     if (senseLength == 0) {
  619.      printf("Warning: SCSI Disk error: no sense data\n");
  620.      *errorStatusPtr = DEV_NO_SENSE;
  621.      return DEV_NO_SENSE;
  622.     }
  623.     if (DevScsiMapClass7Sense(senseLength, senseDataPtr,&status, errorString)) {
  624.     if (errorString[0]) {
  625.          printf("Warning: SCSI Disk  error: %s\n", errorString);
  626.     }
  627.         *errorStatusPtr = status;
  628.     return status;
  629.     }
  630.  
  631.     /*
  632.      * If its not a class 7 error it must be Old style sense data..
  633.      */
  634.     if (sensePtr->error == SCSI_NO_SENSE_DATA) {        
  635.     status = SUCCESS;
  636.     } else {
  637.     int class = (sensePtr->error & 0x70) >> 4;
  638.     int code = sensePtr->error & 0xF;
  639.     int addr;
  640.     addr = (sensePtr->highAddr << 16) |
  641.         (sensePtr->midAddr << 8) |
  642.         sensePtr->lowAddr;
  643.     printf("Warning: SCSI disk sense error (%d-%d) at <%x> ",
  644.             class, code, addr);
  645.     if (devScsiNumErrors[class] > code) {
  646.         printf("%s", devScsiErrors[class][code]);
  647.      }
  648.      printf("\n");
  649.      status = DEV_HARD_ERROR;
  650.     }
  651.     *errorStatusPtr = status;
  652.     return 0;
  653. }
  654.  
  655. /*
  656.  *----------------------------------------------------------------------
  657.  *
  658.  * IOControlProc --
  659.  *
  660.  *      Do a special operation on a raw SCSI Disk.
  661.  *
  662.  * Results:
  663.  *      None.
  664.  *
  665.  * Side effects:
  666.  *      None.
  667.  *
  668.  *----------------------------------------------------------------------
  669.  */
  670.  
  671. /*ARGSUSED*/
  672. static ReturnStatus
  673. IOControlProc(handlePtr, ioctlPtr, replyPtr)
  674.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  675.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  676.     Fs_IOReply *replyPtr;    /* Size of outBuffer and returned signal */
  677. {
  678.      ScsiDisk    *diskPtr = (ScsiDisk *) handlePtr;
  679.      ReturnStatus    status = FAILURE;
  680.  
  681.      if ((ioctlPtr->command & ~0xffff) == IOC_SCSI) {
  682.      status = DevScsiIOControl(diskPtr->devPtr, ioctlPtr, replyPtr);
  683.      return status;
  684.  
  685.      }
  686.      switch (ioctlPtr->command) {
  687.     case    IOC_REPOSITION:
  688.         /*
  689.          * Reposition is ok
  690.          */
  691.         return(SUCCESS);
  692.         /*
  693.          * No disk specific bits are set this way.
  694.          */
  695.     case    IOC_GET_FLAGS:
  696.     case    IOC_SET_FLAGS:
  697.     case    IOC_SET_BITS:
  698.     case    IOC_CLEAR_BITS:
  699.         return(SUCCESS);
  700.  
  701.     case    IOC_GET_OWNER:
  702.     case    IOC_SET_OWNER:
  703.         return(GEN_NOT_IMPLEMENTED);
  704.  
  705.     case    IOC_TRUNCATE:
  706.         return(GEN_INVALID_ARG);
  707.  
  708.     case    IOC_LOCK:
  709.     case    IOC_UNLOCK:
  710.         return(GEN_NOT_IMPLEMENTED);
  711.  
  712.     case    IOC_NUM_READABLE:
  713.         return(GEN_NOT_IMPLEMENTED);
  714.  
  715.     case    IOC_MAP:
  716.         return(GEN_NOT_IMPLEMENTED);
  717.  
  718.     /*
  719.      * This code is for the raid people to test out HBA/disks pairs 
  720.      * by bypassing most of Sprite.
  721.      * Mendel 9/12/89
  722.      */
  723.     case   IOC_HBA_DISK_IO_TEST: {
  724.         register int count, i;
  725.         register DevHBADiskTest  *cmds;
  726.         ScsiCmd    *scsiCmds;
  727.         ReturnStatus       errorStatus;
  728.         static  char *dmaMem, *dmem;
  729.         char *mem;
  730.         static int referCount = 0;
  731.  
  732.         if ((ioctlPtr->inBufSize % sizeof(DevHBADiskTest)) || 
  733.         !ioctlPtr->inBufSize) {
  734.         return(GEN_INVALID_ARG);
  735.         }
  736.         count = ioctlPtr->inBufSize / sizeof(DevHBADiskTest);
  737.         cmds = (DevHBADiskTest  * ) ioctlPtr->inBuffer;
  738.         mem = malloc(sizeof(ScsiCmd)*count);
  739.         if (referCount == 0) { 
  740.             dmem = malloc(128*1024);
  741. #if defined(sun4) || defined(sun3)
  742.             dmaMem = VmMach_DMAAlloc(128*1024, dmem);
  743.             if (dmaMem == (Address) NIL) {
  744.             panic("IOControlProc: unable to allocate dma memory.");
  745.             }
  746. #else
  747.             dmaMem = dmem;
  748. #endif
  749.         } 
  750.         referCount++;
  751.         scsiCmds = (ScsiCmd *) (mem);
  752.         errorStatus = 0;
  753.         for (i = 0; i < count; i++) {
  754.         DevScsiGroup0Cmd(diskPtr->devPtr, 
  755.                 cmds[i].writeOperation ? SCSI_WRITE : SCSI_READ,
  756.                 cmds[i].firstSector, cmds[i].lengthInSectors,
  757.                 &(scsiCmds[i]));
  758.         scsiCmds[i].buffer = dmaMem;
  759.         scsiCmds[i].bufferLen = cmds[i].lengthInSectors * 
  760.                             SCSI_DISK_SECTOR_SIZE;
  761.             scsiCmds[i].dataToDevice = cmds[i].writeOperation;
  762.         scsiCmds[i].clientData = (ClientData) &errorStatus;
  763.             scsiCmds[i].doneProc = DiskHBATestDoneProc;
  764.         if (i < count - 1) {
  765.             DevScsiSendCmd(diskPtr->devPtr, &(scsiCmds[i]));
  766.         } else {
  767.             unsigned char statusByte;
  768.             int    byteCount;
  769.             status = DevScsiSendCmdSync(diskPtr->devPtr,
  770.                 &(scsiCmds[i]),&statusByte,&byteCount,
  771.                  (int *) NIL, (char *) NIL);
  772.         }
  773.        }
  774.        referCount--;
  775.        if (referCount == 0) {
  776. #if defined(sun4) || defined(sun3)
  777.            VmMach_DMAFree(128*1024, dmaMem);
  778. #endif
  779.            free(dmem);
  780.        }
  781.        free(mem);
  782.        if (status) {
  783.            return status;
  784.         }
  785.        return errorStatus;
  786.  
  787.     }
  788.     case   IOC_HBA_DISK_UNIT_TEST: {
  789.         register int count, i;
  790.         register ScsiCmd    *scsiCmds;
  791.         ReturnStatus       errorStatus;
  792.  
  793.         if (ioctlPtr->inBufSize != sizeof(int)) {
  794.         return(GEN_INVALID_ARG);
  795.         }
  796.         count = *(int *) ioctlPtr->inBuffer;
  797.         if ((count < 0) || (count > MAX_HBA_UNIT_TESTS)) {
  798.         return(GEN_INVALID_ARG);
  799.         }
  800.         scsiCmds = (ScsiCmd *) malloc(sizeof(ScsiCmd)*count);
  801.         errorStatus = 0;
  802.         for (i = 0; i < count; i++) {
  803.         DevScsiGroup0Cmd(diskPtr->devPtr, SCSI_TEST_UNIT_READY,
  804.                 0, 0, scsiCmds + i);
  805.         scsiCmds[i].buffer = (char *) NIL;
  806.         scsiCmds[i].bufferLen = 0;
  807.             scsiCmds[i].dataToDevice = 0;
  808.         scsiCmds[i].clientData = (ClientData) &errorStatus;
  809.             scsiCmds[i].doneProc = DiskHBATestDoneProc;
  810.         if (i < count - 1) {
  811.             DevScsiSendCmd(diskPtr->devPtr, &(scsiCmds[i]));
  812.         } else {
  813.             unsigned char statusByte;
  814.             int    byteCount;
  815.             status = DevScsiSendCmdSync(diskPtr->devPtr,
  816.                 &(scsiCmds[i]),&statusByte,&byteCount,
  817.                  (int *) NIL, (char *) NIL);
  818.         }
  819.        }
  820.        free((char *) scsiCmds);
  821.        if (status) {
  822.            return status;
  823.         }
  824.        return errorStatus;
  825.  
  826.     }
  827.     default:
  828.         return(GEN_INVALID_ARG);
  829.     }
  830. }
  831.  
  832. /*
  833.  *----------------------------------------------------------------------
  834.  *
  835.  * ReleaseProc --
  836.  *
  837.  *    Block device release proc.
  838.  *
  839.  * Results:
  840.  *    None.
  841.  *
  842.  * Side effects:
  843.  *    None.
  844.  *
  845.  *----------------------------------------------------------------------
  846.  */
  847. /*ARGUSED*/
  848. static ReturnStatus
  849. ReleaseProc(handlePtr)
  850.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  851. {
  852.     ReturnStatus status;    
  853.     ScsiDisk    *diskPtr = (ScsiDisk *) handlePtr;
  854.  
  855.     status = DevScsiReleaseDevice(diskPtr->devPtr);
  856.     DevDiskUnregister(diskPtr->diskStatsPtr);
  857.     free((char *) diskPtr);
  858.  
  859.     return status;
  860. }
  861.  
  862. /*
  863.  *----------------------------------------------------------------------
  864.  *
  865.  * BlockIOProc --
  866.  *
  867.  *    Convert a Block device IO request in a SCSI command block and 
  868.  *    submit it to the HBA.
  869.  *
  870.  * Results:
  871.  *    The return code from the I/O operation.
  872.  *
  873.  * Side effects:
  874.  *    The disk write, if operation == FS_WRITE.
  875.  *
  876.  *----------------------------------------------------------------------
  877.  */
  878.  
  879. static ReturnStatus
  880. BlockIOProc(handlePtr, requestPtr) 
  881.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  882.     DevBlockDeviceRequest *requestPtr; /* IO Request to be performed. */
  883. {
  884.     ReturnStatus status;    
  885.     ScsiDisk    *diskPtr = (ScsiDisk *) handlePtr;
  886.     unsigned int    firstSector, lengthInSectors, lastSector;
  887.  
  888.  
  889.     if (!((requestPtr->operation == FS_READ) ||
  890.           (requestPtr->operation == FS_WRITE))) {
  891.     panic("Unknown operation %d in ScsiDisk blockIOProc.\n", 
  892.         requestPtr->operation);
  893.     return DEV_INVALID_ARG;
  894.     }
  895.     /*
  896.      * Insure that the request is within the bounds of the partition.
  897.      */
  898.     firstSector = requestPtr->startAddress/DEV_BYTES_PER_SECTOR;
  899.     lengthInSectors = requestPtr->bufferLen/DEV_BYTES_PER_SECTOR;
  900.     lastSector = (diskPtr->partition == WHOLE_DISK_PARTITION) ?
  901.                 (diskPtr->sizeInSectors - 1)  :
  902.             diskPtr->map[diskPtr->partition].firstSector +
  903.                     diskPtr->map[diskPtr->partition].sizeInSectors - 1;
  904.     if (firstSector > lastSector) {
  905.     /*
  906.      * The offset is past the end of the partition.
  907.      */
  908.     printf("BlockIOProc: firstSector(%d) > lastSector (%d)\n",
  909.                             firstSector, lastSector);
  910.     RequestDone(requestPtr,SUCCESS,0);
  911.     return SUCCESS;
  912.     } 
  913.     if (((firstSector + lengthInSectors - 1) > lastSector)) {
  914.     /*
  915.      * The transfer is at the end of the partition.  Reduce the
  916.      * sector count so there is no overrun.
  917.      */
  918.     lengthInSectors = lastSector - firstSector + 1;
  919.     } 
  920.     if (diskPtr->partition != WHOLE_DISK_PARTITION) {
  921.     /*
  922.      * Relocate the disk address to be relative to this partition.
  923.      */
  924.     firstSector += diskPtr->map[diskPtr->partition].firstSector;
  925.     }
  926.  
  927.     status = SendCmdToDevice(diskPtr, requestPtr, firstSector, lengthInSectors);
  928.     return(status);
  929. }
  930.  
  931. /*
  932.  *----------------------------------------------------------------------
  933.  *
  934.  * DevScsiDiskAttach --
  935.  *
  936.  *    Attach a SCSI Disk device to the system.
  937.  *
  938.  * Results:
  939.  *    The DevBlockDeviceHandle of the device.
  940.  *
  941.  * Side effects:
  942.  *    None.
  943.  *
  944.  *----------------------------------------------------------------------
  945.  */
  946.  
  947. DevBlockDeviceHandle *
  948. DevScsiDiskAttach(devicePtr)
  949.     Fs_Device    *devicePtr;    /* The device to attach. */
  950. {
  951.     ScsiDevice    *devPtr;
  952.     ScsiDisk    *diskPtr;
  953.  
  954.     /*
  955.      * Ask the HBA to set up the path to the device. For the time being
  956.      * we will not sort the disk requests.
  957.      */
  958.     devPtr = DevScsiAttachDevice(devicePtr, DEV_QUEUE_FIFO_INSERT);
  959.     if (devPtr == (ScsiDevice *) NIL) {
  960.     return (DevBlockDeviceHandle *) NIL;
  961.     }
  962.     /*
  963.      * Determine the type of device from the inquiry return by the
  964.      * attach. Reject device if not of disk type. If the target 
  965.      * didn't respond to the INQUIRY command we assume that it
  966.      * just a stupid disk.
  967.      */
  968.     if ((devPtr->inquiryLength > 0) &&
  969.     (((ScsiInquiryData *) (devPtr->inquiryDataPtr))->type != 
  970.                             SCSI_DISK_TYPE)) {
  971.     (void) DevScsiReleaseDevice(devPtr);
  972.     return (DevBlockDeviceHandle *) NIL;
  973.     }
  974.     /*
  975.      * Initialize the ScsiDisk structure. We don't need to read the label
  976.      * if the user is opening the device in raw (non partitioned) mode.
  977.      */
  978.     diskPtr = InitDisk(devPtr,DISK_IS_PARTITIONED(devicePtr));
  979.     if (diskPtr == (ScsiDisk *) NIL) {
  980.     return (DevBlockDeviceHandle *) NIL;
  981.     }
  982.     /*
  983.      * Register this disk with the Disk stat routines.
  984.      */
  985.     {
  986.     Fs_Device rawDevice;
  987.  
  988.     rawDevice = *devicePtr;
  989.     rawDevice.unit = rawDevice.unit & ~0xf;
  990.     diskPtr->diskStatsPtr = DevRegisterDisk(&rawDevice,
  991.                           devPtr->locationName,
  992.                           ScsiDiskIdleCheck, 
  993.                           (ClientData) diskPtr);
  994.     }
  995.     diskPtr->partition = DISK_IS_PARTITIONED(devicePtr) ? 
  996.                     DISK_PARTITION(devicePtr) :
  997.                     WHOLE_DISK_PARTITION;
  998.     diskPtr->blockHandle.blockIOProc = BlockIOProc;
  999.     diskPtr->blockHandle.releaseProc = ReleaseProc;
  1000.     diskPtr->blockHandle.IOControlProc = IOControlProc;
  1001.     diskPtr->blockHandle.minTransferUnit = SCSI_DISK_SECTOR_SIZE;
  1002.     diskPtr->blockHandle.maxTransferSize = devPtr->maxTransferSize;
  1003.     return (DevBlockDeviceHandle *) diskPtr;
  1004. }
  1005.  
  1006.  
  1007.